//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
    using Microsoft.Research.ScientificWorkflow.TridentComposer;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Research.DataLayer;
    using TridentAPI;
    using SR = Microsoft.Research.DataLayer;

    /// <summary>
    /// Interaction logic for PropertiesPane.xaml
    /// </summary>
    public partial class PropertiesPane : UserControl, INotifyPropertyChanged
    {
        #region Private Variables

        /// <summary>
        /// The activity model the tree represents.
        /// </summary>
        private BaseModel actModel;

        /// <summary>
        /// The workflow model.
        /// </summary>
        private TridentWorkflowModel wfModel;

        /// <summary>
        /// Flag indicating if the combo box selection was done in code or not.
        /// </summary>
        private bool setInCode;

        /// <summary>
        /// Fired when the user wants to close the property pane.
        /// </summary>
        public event EventHandler ClosePropPane;

        /// <summary>
        /// Fired when the user clicks ok in the property pane.
        /// </summary>
        public event EventHandler OnSaveClicked;

        /// <summary>
        /// RegistryConnection.
        /// </summary>
        private SR.Connection registryConnection;

        /// <summary>
        /// The categoryPicker holder.
        /// </summary>
        private Window categoryPickerWindow;

        /// <summary>
        /// CategoryPicker control.
        /// </summary>
        private CategoryPicker categoryPicker;

        /// <summary>
        /// The composer control holding this element.
        /// </summary>
        private ComposerControl composerCtrl;

        /// <summary>
        /// Holds name of the category.
        /// </summary>
        private string categoryNameHolder;

        /// <summary>
        /// The parameter models which need to be validated.
        /// </summary>
        private List<ParameterDescriptionModel> paramsToValidate = new List<ParameterDescriptionModel>();

        /// <summary>
        /// Flag which checks if the workflow name is valid.
        /// </summary>
        private bool isWorkflowNameValid = true;

        /// <summary>
        /// Flag which checks if the workflow category is valid.
        /// </summary>
        private bool isWorkflowCategoryValid = true;

        /// <summary>
        /// The cloned back up model, in case the user cancels his entered data.
        /// </summary>
        private TridentWorkflowModel backUpWfModel;

        /// <summary>
        /// Occurs on prop pane drag.
        /// </summary>
        public event EventHandler<MouseButtonEventArgs> OnPropPaneDrag;

        /// <summary>
        /// The property treeview 
        /// </summary>
        private TreeView treeVw;

        /// <summary>
        /// The workflow required listview.
        /// </summary>
        private PropertyListControl listVw;

        /// <summary>
        /// Workflow output parameters view.
        /// </summary>
        private OutputPropertyListControl workflowOutputListVw;

        /// <summary>
        /// Collection of binding expressions that hold the updated values.
        /// </summary>
        private Collection<BindingExpression> updatedBindings;

        #endregion Private Variables

        #region Public Properties

        /// <summary>
        /// Gets or sets the variable that holds the pre-validation name of the category.
        /// </summary>
        public string CategoryNameHolder
        {
            get
            {
                return this.categoryNameHolder;
            }

            set
            {
                this.categoryNameHolder = value;
                BindingExpression bindingExp = this.txtBxWfCategory.GetBindingExpression(TextBox.TextProperty);
                if (bindingExp != null)
                {
                    bindingExp.UpdateTarget();
                    if (!string.IsNullOrEmpty(this.txtBxWfCategory.Text))
                    {
                        this.txtBxWfCategory.ToolTip = this.txtBxWfCategory.Text;
                    }
                    else
                    {
                        this.txtBxWfCategory.ToolTip = null;
                    }
                }
            }
        }

        /// <summary>
        /// Gets and sets the activity model.
        /// </summary>
        public BaseModel ActivityModel
        {
            get
            {
                return this.actModel;
            }

            set
            {
                this.actModel = value;
                Mode = PropertyPaneMode.Dockable;
                ShowOptionalProperties = true;
                PropertiesPane.IsErrorPopup = false;
                this.WFModel = null;

                this.UpdateTreeView();
                this.txtBlkPropPaneHeader.Text = TridentResourceManager.GetString("ActivityPropertiesPaneHeader");
            }
        }

        /// <summary>
        /// Gets and sets the workflow model.
        /// </summary>
        public TridentWorkflowModel WFModel
        {
            get
            {
                return this.wfModel;
            }

            set
            {
                this.wfModel = value;
                Mode = PropertyPaneMode.Dockable;
                ShowOptionalProperties = true;
                PropertiesPane.IsErrorPopup = false;

                if (null == this.wfModel)
                {
                    this.dckWfDetails.Visibility = Visibility.Collapsed;
                    this.InitializeBorderView();
                }
                else
                {
                    this.ActivityModel = this.wfModel.Root;
                    this.wfModel = value;
                    this.InitializeTabbedView();
                }
                this.CreateWfModelBackUp();
            }
        }

        /// <summary>
        /// Gets the warning textblock.
        /// </summary>
        public TextBlock TxtBlkWarning
        {
            get
            {
                return this.txtBlkWarningText;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public PropertyPaneMode Mode
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public static bool ShowOptionalProperties
        {
            get;
            set;
        }

        /// <summary>
        /// Flag to check if the property pane is opened in error popup mode.
        /// </summary>
        public static bool IsErrorPopup
        {
            get;
            set;
        }

        /// <summary>
        /// Flag to check if all the properties have valid values.
        /// </summary>
        public static readonly DependencyProperty PropertiesValidProperty =
        DependencyProperty.Register("PropertiesValid", typeof(Boolean), typeof(PropertiesPane), new PropertyMetadata(true));

        /// <summary>
        /// Flag to check if all the properties have valid values.
        /// </summary>
        public bool PropertiesValid
        {
            get { return (bool)GetValue(PropertiesValidProperty); }
            set { SetValue(PropertiesValidProperty, value); }
        }

        public User User { get; set; }

        #endregion Public properties

        #region Constructors

        /// <summary>
        /// Private constructor.
        /// </summary>
        private PropertiesPane(SR.Connection connection)
        {
            this.Initializer(connection);
            this.User = TridentAuthentication.LoggedInUser;
        }

        /// <summary>
        /// Property pane, displaying only the activity details.
        /// </summary>
        /// <param name="actModel">
        /// The activity model, the details of which are to be displayed.
        /// </param>
        public PropertiesPane(SR.Connection connection, BaseModel actModel)
            : this(connection)
        {
            this.ActivityModel = actModel;
        }

        /// <summary>
        /// Property pane, displaying the workflow properties and those of all it's activities.
        /// </summary>
        /// <param name="wfModel">
        /// WorkflowModel to be shown.
        /// </param>
        public PropertiesPane(SR.Connection connection, TridentWorkflowModel workflowModel)
            : this(connection)
        {
            this.WFModel = workflowModel;
        }

        /// <summary>
        /// Property pane, displaying the workflow properties and those of all it's activities.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="wfModel">WorkflowModel to be shown.</param>
        /// <param name="showWorkflowParameters">if set to <c>true</c> shows workflow parameters tab.</param>
        public PropertiesPane(SR.Connection connection, TridentWorkflowModel workflowModel, bool showWorkflowParameters)
            : this(connection, workflowModel)
        {
            if (showWorkflowParameters)
            {
                this.ShowWorkflowParametersTab();
            }
        }

        /// <summary>
        /// Property pane, displaying the workflow properties and those of all it's activities.
        /// </summary>
        /// <param name="wfModel">
        /// WorkflowModel to be shown.
        /// </param>
        public PropertiesPane(SR.Connection connection, TridentWorkflowModel workflowModel, PropertyPaneMode mode, bool showOptionalProperties)
            : this(connection, workflowModel)
        {
            Mode = mode;
            ShowOptionalProperties = showOptionalProperties;
            if (Mode == PropertyPaneMode.Popup)
            {
                this.btnOk.Visibility = Visibility.Visible;
                this.btnCancel.Visibility = Visibility.Visible;
                this.sprtr.Visibility = Visibility.Visible;
                this.txtMandatoryParams.Visibility = Visibility.Visible;
                this.imgWarningIcon.Visibility = Visibility.Visible;
                this.btnPropPaneClose.Visibility = Visibility.Visible;
                this.btnPropPaneRefresh.Visibility = Visibility.Collapsed;
                this.txtBlkEditWfCategory.IsEnabled = true;
            }
            else if (Mode == PropertyPaneMode.Dockable)
            {
                this.btnOk.Visibility = Visibility.Collapsed;
                this.btnCancel.Visibility = Visibility.Collapsed;
                this.sprtr.Visibility = Visibility.Collapsed;
                this.txtMandatoryParams.Visibility = Visibility.Collapsed;
                this.imgWarningIcon.Visibility = Visibility.Collapsed;
                this.btnPropPaneClose.Visibility = Visibility.Visible;
                this.btnPropPaneRefresh.Visibility = Visibility.Visible;
            }
            else if (Mode == PropertyPaneMode.Fixed)
            {
                this.btnOk.Visibility = Visibility.Collapsed;
                this.btnCancel.Visibility = Visibility.Collapsed;
                this.sprtr.Visibility = Visibility.Collapsed;
                this.txtMandatoryParams.Visibility = Visibility.Visible;
                this.imgWarningIcon.Visibility = Visibility.Visible;
                this.btnPropPaneClose.Visibility = Visibility.Collapsed;
                this.btnPropPaneRefresh.Visibility = Visibility.Collapsed;
                this.dckWfDetails.Visibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// Property pane, displaying the workflow properties and those of all it's activities.
        /// </summary>
        /// <param name="wfModel">
        /// WorkflowModel to be shown.
        /// </param>
        public PropertiesPane(SR.Connection connection, TridentWorkflowModel workflowModel, PropertyPaneMode mode, bool showOptionalProperties, bool showActivityProperties)
            : this(connection, workflowModel, mode, showOptionalProperties)
        {
            if (!showActivityProperties)
            {
                this.brdrTreeVeHolder.Visibility = Visibility.Collapsed;
                this.sprtr.Visibility = Visibility.Collapsed;
                this.txtMandatoryParams.Visibility = Visibility.Collapsed;
                this.imgWarningIcon.Visibility = Visibility.Collapsed;
                this.rowMainHolder.Height = new GridLength(0, GridUnitType.Auto);
                this.Width = 400;
            }
        }

        /// <summary>
        /// Property pane, displaying the workflow properties and those of all it's activities.
        /// </summary>
        /// <param name="wfModel">
        /// WorkflowModel to be shown.
        /// </param>
        public PropertiesPane(SR.Connection connection, TridentWorkflowModel workflowModel, PropertyPaneMode mode, bool showOptionalProperties, bool showActivityProperties, bool openedFromSaveAs)
            : this(connection, workflowModel, mode, showOptionalProperties, showActivityProperties)
        {
            // Clear the workflow Id if its opened from the  save as 
            if (openedFromSaveAs)
            {
                this.wfModel.ClearId();
            }
        }

        /// <summary>
        /// Property pane, displaying the workflow properties and those of all it's activities.
        /// </summary>
        /// <param name="connection">
        /// Registry connection.
        /// </param>
        /// <param name="model">
        /// WorkflowModel to be shown.
        /// </param>
        /// <param name="mode">
        /// Display mode of this dialog.
        /// </param>
        /// <param name="errorPopupMode">
        /// Error popup mode.
        /// </param>
        public PropertiesPane(SR.Connection connection, BaseModel model, PropertyPaneMode mode, bool errorPopupMode)
        {
            if (errorPopupMode)
            {
                this.Initializer(connection);
                this.ActivityModel = model;
                PropertiesPane.IsErrorPopup = errorPopupMode;
                this.btnOk.Visibility = Visibility.Visible;
                this.btnCancel.Visibility = Visibility.Visible;
                this.sprtr.Visibility = Visibility.Visible;
                this.txtMandatoryParams.Visibility = Visibility.Visible;
                this.imgWarningIcon.Visibility = Visibility.Visible;
                this.btnPropPaneRefresh.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.Initializer(connection);
                this.ActivityModel = model;
                PropertiesPane.IsErrorPopup = errorPopupMode;
                this.btnOk.Visibility = Visibility.Collapsed;
                this.btnCancel.Visibility = Visibility.Collapsed;
                this.sprtr.Visibility = Visibility.Collapsed;
                this.txtMandatoryParams.Visibility = Visibility.Collapsed;
                this.imgWarningIcon.Visibility = Visibility.Collapsed;
                this.btnPropPaneRefresh.Visibility = Visibility.Visible;
            }

            this.Mode = mode;
        }

        #endregion Constructors.

        /// <summary>
        /// Shows the workflow parameters tab.
        /// </summary>
        public void ShowWorkflowParametersTab()
        {
            this.propertyTreeHostTab.SelectedIndex = 1;
        }

        /// <summary>
        /// Add parameters to the input parameter list. 
        /// This is required when the property pane is open and the user makes a property mandatory for workflow.
        /// </summary>
        /// <param name="paramModel">The parameter model.</param>
        /// <param name="addParameter">True to add to the list, False otherwise.</param>
        public void UpdateInputParameters(ParameterDescriptionModel parameterModel, bool addParameter)
        {
            if (!this.listVw.Parameters.Contains(parameterModel) && addParameter)
            {
                this.listVw.Parameters.Add(parameterModel);
            }
            else if (this.listVw.Parameters.Contains(parameterModel) && !addParameter)
            {
                this.listVw.Parameters.Remove(parameterModel);
            }
        }

        #region Private Methods

        /// <summary>
        /// Does the initial assignments.
        /// </summary>
        /// <param name="connection">
        /// The connection object for this instance.
        /// </param>
        private void Initializer(SR.Connection connection)
        {
            InitializeComponent();
            if (null != connection)
            {
                this.registryConnection = connection;
            }

            this.updatedBindings = new Collection<BindingExpression>();

            this.treeVw = new TreeView();
            this.treeVw.FocusVisualStyle = this.FindResource("TreeViewFocusVisual") as Style;
            this.treeVw.ItemTemplateSelector = this.FindResource("ParamTemplateSelector") as DataTemplateSelector;
            this.treeVw.RequestBringIntoView += TextBox_RequestBringIntoView;

            Mode = PropertyPaneMode.Dockable;
            ShowOptionalProperties = true;
            PropertiesPane.IsErrorPopup = false;
            this.Loaded += new RoutedEventHandler(this.OnPropertiesPaneLoaded);

            // Initialize the workflow required property list.
            this.listVw = new PropertyListControl(new Collection<ParameterDescriptionModel>(), ValidationMode.InvalidValue);

            // Initialize the workflow output property list in edit mode.
            this.workflowOutputListVw = new OutputPropertyListControl(new Collection<ParameterDescriptionModel>(), ControlMode.Edit);
        }

        /// <summary>
        /// Updates the details of the workflow.
        /// </summary>
        /// <param name="wfModel">
        /// The workflowModel.
        /// </param>
        private void UpdateWorkflowDetails(TridentWorkflowModel wfModel)
        {
            this.dckWfDetails.Visibility = Visibility.Visible;

            Binding nameBinding = new Binding("Name");
            nameBinding.Mode = BindingMode.TwoWay;
            nameBinding.Source = wfModel;
            nameBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
            this.txtBxWfName.SetBinding(TextBox.TextProperty, nameBinding);
            if (!string.IsNullOrEmpty(this.txtBxWfName.Text))
            {
                this.txtBxWfName.ToolTip = this.txtBxWfName.Text;
            }
            else
            {
                this.txtBxWfName.ToolTip = null;
            }

            Binding descBinding = new Binding("Description");
            descBinding.Mode = BindingMode.TwoWay;
            descBinding.Source = wfModel;
            descBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
            this.txtBxWfDesc.SetBinding(TextBox.TextProperty, descBinding);
            if (!string.IsNullOrEmpty(this.txtBxWfDesc.Text))
            {
                this.txtBxWfDesc.ToolTip = this.txtBxWfDesc.Text;
            }
            else
            {
                this.txtBxWfDesc.ToolTip = null;
            }

            if (this.wfModel.Category != null && this.wfModel.OwnerOrAdmin)
            {
                if (this.CheckExistsInBaseTree())
                {
                    this.CategoryNameHolder = this.wfModel.Category.Label;
                }
                else
                {
                    this.CategoryNameHolder = this.wfModel.Owner;
                }

                this.isWorkflowCategoryValid = true;
                this.ChangeWfCategoryErrorMarkerVisibility(false, TridentResourceManager.GetString("PropertyPaneCategoryContainsName"));
            }
            else
            {
                if (this.wfModel.Category != null)
                {
                    if (this.wfModel.Category.RootCategory.Parent == null &&
                        this.CheckExistsInBaseTree())
                    {
                        this.CategoryNameHolder = this.wfModel.Category.Label;
                    }
                    else
                    {
                        this.CategoryNameHolder = this.wfModel.Owner;
                    }
                }

                this.isWorkflowCategoryValid = false;
                this.ChangeWfCategoryErrorMarkerVisibility(true, TridentResourceManager.GetString("PropertyPaneCategoryEmpty"));
            }
            this.SetCategory();
        }

        /// <summary>
        /// Checks the existence of the workflow in the base workflow tree.
        /// </summary>
        /// <returns></returns>
        private bool CheckExistsInBaseTree()
        {
            return (this.wfModel.Category.RootCategory.CategoryUserId == ((IObject)TridentAuthentication.LoggedInUser).ID ||
                this.wfModel.Category.RootCategory.CategoryUserId == ((IObject)TridentAuthentication.SystemUser).ID ||
                this.wfModel.Category.RootCategory.CategoryUserId == Guid.Empty);
        }

        /// <summary>
        /// 
        /// </summary>
        private void SetCategory()
        {
            Binding categoryBinding = new Binding("CategoryNameHolder");
            categoryBinding.Mode = BindingMode.OneWay;
            categoryBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            categoryBinding.Source = this;
            this.txtBxWfCategory.SetBinding(TextBox.TextProperty, categoryBinding);
            if (!string.IsNullOrEmpty(this.txtBxWfCategory.Text))
            {
                this.txtBxWfCategory.ToolTip = this.txtBxWfCategory.Text;
            }
            else
            {
                this.txtBxWfCategory.ToolTip = null;
            }
        }

        private void LoadWorkflowType()
        {
            if (this.WFModel.IsInteractive)
            {
                this.cmbWorkflowType.SelectedIndex = 0;
            }
            else
            {
                this.cmbWorkflowType.SelectedIndex = 1;
            }
        }

        private bool SelectedWorkflowType()
        {
            if (this.cmbWorkflowType.SelectedIndex == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Show the tabbed view of the property pane, with workflow required properties in a saperate tab.
        /// </summary>
        private void InitializeTabbedView()
        {
            this.UpdateWorkflowDetails(this.wfModel);
            this.txtBlkPropPaneHeader.Text = TridentResourceManager.GetString("WorkflowPropertiesPaneHeader");
            this.OnWfNameTextBoxLostFocus(null, new RoutedEventArgs());
            this.LoadWorkflowType();

            // Make the treeview border invisible and add the tree to the tab.
            this.propertyTreeHostTab.Visibility = Visibility.Visible;
            this.propertyTreeHostBorder.Visibility = Visibility.Collapsed;

            if (treeVw.Parent != null)
            {
                Border parent = this.treeVw.Parent as Border;
                parent.Child = null;
            }
            this.propertyTreeHost.Child = this.treeVw;

            // Add the required parameter list to the tab.
            if (this.listVw != null)
            {
                if (listVw.Parent == null)
                {
                    this.propertyListHost.Child = this.listVw;
                }
                this.listVw.UpdateList(this.wfModel.GetWorkflowRequiredParameters());
            }

            // Add the workflow output parameter list to the tab.
            if (this.workflowOutputListVw != null)
            {
                if (this.workflowOutputListVw.Parent == null)
                {
                    this.workflowOutputListHost.Child = this.workflowOutputListVw;
                }
                this.workflowOutputListVw.UpdateList(this.wfModel.GetWorkflowOutputParameters());
            }

            this.txtBlkEditWfCategory.IsEnabled = this.wfModel.OwnerOrAdmin;
        }

        /// <summary>
        /// Show only the property treeview. Hide the workflow required parameters list.
        /// </summary>
        private void InitializeBorderView()
        {
            // Make the treeview tab invisible and add the tree to the border.
            this.propertyTreeHostTab.Visibility = Visibility.Collapsed;
            this.propertyTreeHostBorder.Visibility = Visibility.Visible;
            if (treeVw.Parent != null)
            {
                Border parent = this.treeVw.Parent as Border;
                parent.Child = null;
            }

            this.propertyTreeHostBorder.Child = this.treeVw;

            if (this.listVw != null)
            {
                this.listVw.ClearList();
            }

            if (this.workflowOutputListVw != null)
            {
                this.workflowOutputListVw.ClearList();
            }
        }

        /// <summary>
        /// Update the activity tree.
        /// </summary>
        private void UpdateTreeView()
        {
            this.treeVw.ItemsSource = new ObservableCollection<BaseModel>() { this.actModel };
        }

        /// <summary>
        /// Fired on initialization.
        /// </summary>
        /// <param name="sender">
        /// Param listview.
        /// </param>
        /// <param name="e">
        /// EventArgs.
        /// </param>
        private void OnListViewInitialized(object sender, EventArgs e)
        {
            ListView senderListVw = sender as ListView;
            if (0 == senderListVw.Items.Count)
            {
                senderListVw.Visibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// On mouse wheel of the listview.
        /// </summary>
        /// <param name="sender">
        /// Param listview.
        /// </param>
        /// <param name="e">
        /// EventArgs.
        /// </param>
        private void OnListViewPreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            ScrollViewer scrollViewer = null;
            DependencyObject border = VisualTreeHelper.GetChild(this.treeVw, 0);
            if (border != null)
            {
                scrollViewer = VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
            }

            if (scrollViewer != null)
            {
                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
            }
        }

        /// <summary>
        /// Fired on textbox loaded, assigns its width.
        /// </summary>
        /// <param name="sender">
        /// Value textbox.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnInputValueTextBoxLoaded(object sender, RoutedEventArgs e)
        {
            ((sender as TextBox).TemplatedParent as ContentPresenter).HorizontalAlignment = HorizontalAlignment.Stretch;

            TextBox txtBx = sender as TextBox;
            BindingExpression bindingExp = txtBx.GetBindingExpression(TextBox.TextProperty);
            this.ValidateInputValues(txtBx.Text, bindingExp, txtBx);
        }

        /// <summary>
        /// On lost focus of the value textbox, does validations.
        /// </summary>
        /// <param name="sender">
        /// Value textbox.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnInputValueTextBoxLostFocus(object sender, RoutedEventArgs e)
        {
            TextBox txtBx = sender as TextBox;
            DockPanel errorDck = (txtBx.Parent as Grid).FindName("errorDck") as DockPanel;
            BindingExpression bindingExp = txtBx.GetBindingExpression(TextBox.TextProperty);

            // Validate the input values.
            this.ValidateInputValues(txtBx.Text, bindingExp, txtBx);

            // If it is a popup, add the updated binding to the collection.
            if (this.Mode == PropertyPaneMode.Popup)
            {
                // Check if this particular parameter model is valid or not.
                bool isInvalid = true;
                ParameterDescriptionModel paramModel = errorDck.DataContext as ParameterDescriptionModel;
                if (paramModel != null)
                {
                    isInvalid = !paramModel.IsDatabound && paramModel.IsValueInvalid;
                }

                if (!isInvalid && !this.updatedBindings.Contains(bindingExp))
                {
                    this.updatedBindings.Add(bindingExp);
                }
            }

            if (this.composerCtrl != null)
            {
                this.composerCtrl.IsWFCommitted = false;
            }
        }

        /// <summary>
        /// Fired on loaded of the custom type value text box.
        /// </summary>
        /// <param name="sender">
        /// Custom type value textbox.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnCustomTypeValLoaded(object sender, RoutedEventArgs e)
        {
            TextBox box = sender as TextBox;
            if (box != null)
            {
                MultiBindingExpression multiBindingExp = BindingOperations.GetMultiBindingExpression(box, TextBox.TextProperty);
                if (multiBindingExp != null && multiBindingExp.BindingExpressions.Count > 0)
                {
                    BindingExpression bindingExp = multiBindingExp.BindingExpressions[0] as BindingExpression;
                    this.ValidateInputValues(box.Text, bindingExp, box);
                }
            }
        }

        /// <summary>
        /// Fired on text change of the custom type param text box.
        /// </summary>
        /// <param name="sender">
        /// Custom type input value text box.
        /// </param>
        /// <param name="e">
        /// TextChangedEventArgs.
        /// </param>
        private void OnCustomValueTextChanged(object sender, TextChangedEventArgs e)
        {
            this.OnCustomTypeValLoaded(sender, new RoutedEventArgs());
            if (this.composerCtrl != null)
            {
                this.composerCtrl.IsWFCommitted = false;
            }
        }

        /// <summary>
        /// Used for showing the error containing models. Checks each of the input parameters of the model and 
        /// if any of those have invalid values, will return a Visibility.Visible, else Collapsed.
        /// </summary>
        /// <param name="model">
        /// The model whose visibility requirement is to be checked.
        /// </param>
        /// <returns>
        /// Visible if an error exists, collapsed otherwise.
        /// </returns>
        internal static Visibility CheckModelForWrongInputs(BaseModel model, bool returnFirstInstance)
        {
            Visibility retVal = model.VisibleOnUI.ActivityParametersVisibility;
            if (Visibility.Visible == retVal)
            {
                retVal = Visibility.Collapsed;
                bool containsWrongVal = false;

                // Run through all the child elements and decide the visibility based on those values.
                foreach (ParameterDescriptionModel paramModel in model.InputParameters)
                {
                    string currentVal = paramModel.Value == null ? null : paramModel.Value.ToString();
                    containsWrongVal = !PropertiesPane.ValidateInputValue(currentVal, paramModel);
                    if (containsWrongVal)
                    {
                        if (returnFirstInstance)
                        {
                            retVal = Visibility.Visible;
                            break;
                        }
                        else
                        {

                        }
                    }
                }
            }

            return retVal;
        }

        /// <summary>
        /// Validate the entered value against the requirements of the paramModel.
        /// </summary>
        /// <param name="enteredVal">
        /// The current value.
        /// </param>
        /// <param name="paramDesc">
        /// The parameter model for which the value has been specified.
        /// </param>
        /// <returns>
        /// Returns true if valid value, false otherwise.
        /// </returns>
        private static bool ValidateInputValue(string enteredVal, ParameterDescriptionModel paramDesc)
        {
            bool validValue = true;
            if (paramDesc != null)
            {
                if (string.IsNullOrEmpty(enteredVal))
                {
                    validValue = (paramDesc.IsMandatory && !paramDesc.IsMandatoryForWorkflow) ? false : true;
                }
                else
                {
                    try
                    {
                        TypeInitializer typeInit = TypeProviderHelper.FetchTypeInitializer(paramDesc.DataType, Runtime.WPF);
                        if (typeInit != null)
                        {
                            string deserializedVal = (paramDesc.Value != null) ? paramDesc.Value.ToString() : string.Empty;
                            BaseTypeInitializer baseTypeinit = ActivityComposer.LoadInitializer(typeInit, deserializedVal);
                            if (baseTypeinit != null)
                            {
                                if (paramDesc.IsMandatory)
                                {
                                    validValue = baseTypeinit.ContainsValidValue();
                                }
                                else
                                {
                                    validValue = baseTypeinit.ContainsValidValue() || baseTypeinit.ContainsEmptyValue();
                                }
                            }
                        }
                        else
                        {
                            System.Type dataType = System.Type.GetType(paramDesc.DataType);
                            if (dataType != null)
                            {
                                object parsedValue = System.ComponentModel.TypeDescriptor.GetConverter(dataType).ConvertFromString(enteredVal);
                                if (null == parsedValue)
                                {
                                    validValue = false;
                                }
                            }
                        }
                    }
                    catch (NotSupportedException)
                    {
                        validValue = false;
                    }
                    catch (FormatException)
                    {
                        validValue = false;
                    }
                    catch (Exception)
                    {
                        validValue = false;
                    }
                }
            }

            return validValue;
        }

        /// <summary>
        /// Validates the input values.
        /// </summary>
        /// <param name="enteredVal">
        /// The entered values.
        /// </param>
        /// <param name="bindingExp">
        /// The textbox's binding.
        /// </param>
        /// <param name="errorDck">
        /// The error marker.
        /// </param>
        /// <param name="txtBx">
        /// The textbox.
        /// </param>
        private void ValidateInputValues(string enteredVal, BindingExpression bindingExp, TextBox txtBx)
        {
            if (bindingExp != null && txtBx != null && txtBx.IsVisible)
            {
                ParameterDescriptionModel paramDesc = bindingExp.DataItem as ParameterDescriptionModel;
                paramDesc.IsValueInvalid = !PropertiesPane.ValidateInputValue(enteredVal, paramDesc);

                // Update source only if it is not popup.
                // If it is popup, it'll be updated on Ok click.
                if (this.Mode != PropertyPaneMode.Popup)
                {
                    // Update the paramModel irrespective of whether it is an error or not. The handling of whether the value is valid or not will be done duing save.
                    bindingExp.UpdateSource();
                }

                this.PropertiesValid = this.CheckIfAllValuesValid();
            }
        }

        /// <summary>
        /// Fired on text changed of the input value.
        /// </summary>
        /// <param name="sender">
        /// Input value of the textbox.
        /// </param>
        /// <param name="e">
        /// TextChangedEventArgs.
        /// </param>
        private void OnInputValTextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox txtBox = sender as TextBox;
            if (txtBox != null && !txtBox.IsFocused)
            {
                this.OnInputValueTextBoxLostFocus(sender, new RoutedEventArgs());
            }
        }

        /// <summary>
        /// Fired on refresh click.
        /// </summary>
        /// <param name="sender">
        /// Refresh button.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnPropertyPaneRefreshClick(object sender, RoutedEventArgs e)
        {
            if (null == this.wfModel)
            {
                this.UpdateTreeView();
            }
            else
            {
                this.WFModel = this.wfModel;
                this.listVw.UpdateList(this.wfModel.GetWorkflowRequiredParameters());

                this.workflowOutputListVw.UpdateList(this.wfModel.GetWorkflowOutputParameters());
            }
        }

        private void OnWorkflowTypeChanged(object sender, SelectionChangedEventArgs e)
        {
            this.WFModel.IsInteractive = this.SelectedWorkflowType();
            if (this.composerCtrl != null)
            {
                this.composerCtrl.IsWFCommitted = false;
            }
        }

        /// <summary>
        /// Fired on selection changed of the combo box.
        /// </summary>
        /// <param name="sender">
        /// Combobox.
        /// </param>
        /// <param name="e">
        /// SelectionChangedEventArgs.
        /// </param>
        private void OnDropDownSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox cmbBox = sender as ComboBox;
            int tagVal = -2;
            if (!this.setInCode)
            {
                if (int.TryParse(cmbBox.Tag.ToString(), out tagVal) && -1 == tagVal)
                {
                    for (int iterator = 0; iterator < cmbBox.Items.Count; iterator++)
                    {
                        TridentPropertyBindingObject valObj = cmbBox.Items[iterator] as TridentPropertyBindingObject;
                        if (valObj != null)
                        {
                            if (valObj.Value.Equals(valObj.ParameterDescriptionModel.Value)
                                    || valObj.Key.Equals(valObj.ParameterDescriptionModel.Value))
                            {
                                this.setInCode = true;
                                cmbBox.SelectedIndex = iterator;
                                cmbBox.Tag = -2;
                                this.setInCode = false;
                                break;
                            }
                            else if (null == valObj.ParameterDescriptionModel.Value)
                            {
                                this.setInCode = true;
                                cmbBox.SelectedIndex = iterator;
                                valObj.ParameterDescriptionModel.Value = valObj.Value;
                                valObj.ParameterDescriptionModel.IsDatabound = false;
                                cmbBox.Tag = -2;
                                this.setInCode = false;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    foreach (object obj in e.AddedItems)
                    {
                        TridentPropertyBindingObject changedVal = obj as TridentPropertyBindingObject;
                        changedVal.ParameterDescriptionModel.Value = changedVal.Value;
                        changedVal.ParameterDescriptionModel.IsDatabound = false;
                        if (this.composerCtrl != null)
                        {
                            this.composerCtrl.IsWFCommitted = false;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Fired on click of close of the property pane.
        /// </summary>
        /// <param name="sender">
        /// Close button.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnPropPaneCloseClick(object sender, RoutedEventArgs e)
        {
            if (this.Mode == PropertyPaneMode.Popup)
            {
                this.OnCancelClick(sender, e);
            }
            else if (this.ClosePropPane != null)
            {
                this.ClosePropPane.Invoke(this, e);
            }
        }

        /// <summary>
        /// Fired on click of OK of the property pane.
        /// </summary>
        /// <param name="sender">
        /// Close button.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnOkClick(object sender, RoutedEventArgs e)
        {
            // If it is popup, update all bindings.
            if (this.Mode == PropertyPaneMode.Popup)
            {
                foreach (BindingExpression bindingExp in this.updatedBindings)
                {
                    bindingExp.UpdateSource();
                }
            }

            bool validClose = true;
            this.PropertiesValid = this.CheckIfAllValuesValid();

            if (!this.listVw.PropertiesValid || !this.PropertiesValid || !this.isWorkflowNameValid || !this.isWorkflowCategoryValid)
            {
                validClose = false;
            }

            if (validClose)
            {
                if (this.OnSaveClicked != null)
                {
                    this.OnSaveClicked.Invoke(this, e);
                }
            }
            else
            {
                this.TxtBlkWarning.Visibility = Visibility.Visible;
            }
        }

        /// <summary>
        /// Fired on lost focus of the workflow name textbox, does validations.
        /// </summary>
        /// <param name="sender">
        /// Workflow name textbox.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnWfNameTextBoxLostFocus(object sender, RoutedEventArgs e)
        {
            if (this.wfModel != null)
            {
                try
                {
                    BindingExpression bindingExp = this.txtBxWfName.GetBindingExpression(TextBox.TextProperty);
                    if (bindingExp != null)
                    {
                        bool validUpdate = true;
                        string errorPrompt = string.Empty;

                        // Category model in which to check uniqueness of the wfName.
                        WorkflowCategoryModel requiredModel = this.wfModel.Category;
                        if (this.categoryPicker != null && this.categoryPicker.SelectedModel != null)
                        {
                            requiredModel = this.categoryPicker.SelectedModel;
                        }

                        string enteredString = this.txtBxWfName.Text;

                        if (string.IsNullOrEmpty(enteredString) || string.IsNullOrEmpty(enteredString.Trim()))
                        {
                            validUpdate = false;
                            errorPrompt = TridentResourceManager.GetString("PropertyPaneWfNameEmpty");
                        }
                        else if (!TridentWorkflowModel.CheckNameForInvalidCharacters(enteredString))
                        {
                            validUpdate = false;
                            errorPrompt = TridentResourceManager.GetString("PropertyPaneWfNameInvalidChars");
                        }
                        else if (requiredModel != null && !this.CheckIfWfNameIsUnique(requiredModel, enteredString))
                        {
                            validUpdate = false;
                            this.isWorkflowCategoryValid = false;
                            this.ChangeWfCategoryErrorMarkerVisibility(true, TridentResourceManager.GetString("PropertyPaneCategoryContainsName"));
                            errorPrompt = TridentResourceManager.GetString("InvalidPropertyPaneWfNameInput");
                        }

                        DockPanel errorWfName = (this.txtBxWfName.Parent as Grid).FindName("errorWfName") as DockPanel;
                        if (!validUpdate)
                        {
                            this.isWorkflowNameValid = false;
                            if (this.composerCtrl != null)
                            {
                                this.composerCtrl.IsWFCommitted = false;
                            }

                            if (errorWfName != null)
                            {
                                errorWfName.Visibility = Visibility.Visible;
                                errorWfName.ToolTip = errorPrompt;
                                this.txtBxWfName.ToolTip = errorWfName.ToolTip;
                                bindingExp.UpdateSource();
                            }
                        }
                        else
                        {
                            this.isWorkflowNameValid = true;
                            // Update the workflow category since the uniqueness is established.
                            if (this.categoryPicker != null && this.categoryPicker.SelectedModel != null)
                            {
                                this.wfModel.Category = this.categoryPicker.SelectedModel;
                                this.isWorkflowCategoryValid = true;
                                this.ChangeWfCategoryErrorMarkerVisibility(false, null);
                            }

                            // Collapse the Errormarker if the category name get assigned  
                            if (!string.IsNullOrEmpty(this.txtBxWfCategory.Text))
                            {
                                this.isWorkflowCategoryValid = true;
                                this.ChangeWfCategoryErrorMarkerVisibility(false, null);
                            }

                            if (errorWfName != null)
                            {
                                errorWfName.Visibility = Visibility.Collapsed;
                            }

                            this.txtBxWfName.ToolTip = this.txtBxWfName.Text;
                            if (this.composerCtrl != null && !string.Equals(this.txtBxWfName.Text, this.wfModel.Name))
                            {
                                this.composerCtrl.IsWFCommitted = false;
                            }

                            bindingExp.UpdateSource();
                        }
                    }
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.HandleKnownExceptionsInUI(ex);
                }
            }
        }

        /// <summary>
        /// Fired on lost focus of the workflow description textbox.
        /// </summary>
        /// <param name="sender">
        /// Workflow description textbox.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnWfDescTextBoxLostFocus(object sender, RoutedEventArgs e)
        {
            BindingExpression bindingExp = this.txtBxWfDesc.GetBindingExpression(TextBox.TextProperty);
            if (bindingExp != null)
            {
                bindingExp.UpdateSource();
                if (!string.IsNullOrEmpty(this.txtBxWfDesc.Text))
                {
                    this.txtBxWfDesc.ToolTip = this.txtBxWfDesc.Text;
                }
                else
                {
                    this.txtBxWfDesc.ToolTip = null;
                }

                if (this.composerCtrl != null)
                {
                    this.composerCtrl.IsWFCommitted = false;
                }
            }
        }

        /// <summary>
        /// Brings up the category picker.
        /// </summary>
        /// <param name="sender">
        /// Edit of category.
        /// </param>
        /// <param name="e">
        /// MouseButtonEventArgs.
        /// </param>
        private void OnEditWorkflowCategory(object sender, MouseButtonEventArgs e)
        {
            this.EditWorkflowCategory();
        }

        /// <summary>
        /// Called when there is a key down on edit category.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
        private void OnEditCategoryKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                this.EditWorkflowCategory();
                e.Handled = true;
            }
        }

        /// <summary>
        /// Edits the workflow category.
        /// </summary>
        private void EditWorkflowCategory()
        {
            if (null != this.registryConnection)
            {
                this.txtBxWfCategory.Focus();
                Collection<WorkflowCategoryModel> categories = CategoriesComposer.ReadWorkflowCategoriesFromRegistry(this.registryConnection,
                                                            this.User, true);
                this.categoryPicker = new CategoryPicker(categories);
                this.categoryPicker.CategoryPickerCancel += new EventHandler(this.OnCategoryPickerCancel);
                this.categoryPicker.CategoryPickerOk += new EventHandler(this.OnCategoryPickerOk);
                this.categoryPicker.HeaderDrag += (sender, e) => { this.categoryPickerWindow.DragMove(); };

                this.categoryPickerWindow = new Window();
                this.categoryPickerWindow.Content = this.categoryPicker;
                this.categoryPickerWindow.SizeToContent = SizeToContent.WidthAndHeight;
                this.categoryPickerWindow.ShowInTaskbar = false;
                this.categoryPickerWindow.MinWidth = 250;
                this.categoryPickerWindow.MinHeight = 300;
                this.categoryPickerWindow.MaxHeight = 300;
                this.categoryPickerWindow.MaxWidth = 250;
                this.categoryPickerWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                this.categoryPickerWindow.WindowStyle = WindowStyle.None;
                this.categoryPickerWindow.BorderBrush = new SolidColorBrush(Colors.Transparent);
                this.categoryPickerWindow.BorderThickness = new Thickness(0, 0, 0, 0);
                this.categoryPickerWindow.ResizeMode = ResizeMode.NoResize;
                this.categoryPickerWindow.ShowDialog();
            }
        }

        /// <summary>
        /// Fired on OK click of the category picker.
        /// </summary>
        /// <param name="sender">
        /// The category picker.
        /// </param>
        /// <param name="e">
        /// EventArgs.
        /// </param>
        private void OnCategoryPickerOk(object sender, EventArgs e)
        {
            // Check for the selected category model, see if the unique name constraint is respected.
            // If yes, assign the category to the workflow model directly. Else keep the name in the temp holder and show
            // the error prompt.
            //this.OnWfNameTextBoxLostFocus(this.txtBxWfName, new RoutedEventArgs());
            if (this.wfModel != null && this.categoryPicker != null && this.categoryPicker.SelectedModel != null)
            {
                try
                {
                    bool validUpdate = true;
                    string currentEnteredName = string.Empty;
                    if (!string.IsNullOrEmpty(this.txtBxWfName.Text) && !string.IsNullOrEmpty(this.txtBxWfName.Text.Trim()))
                    {
                        currentEnteredName = this.txtBxWfName.Text.Trim();
                    }

                    this.wfModel.Category = this.categoryPicker.SelectedModel;
                    if (this.composerCtrl != null)
                    {
                        this.composerCtrl.IsWFCommitted = false;
                    }

                    // If valid name.
                    if (!string.IsNullOrEmpty(currentEnteredName) && TridentWorkflowModel.CheckNameForInvalidCharacters(currentEnteredName))
                    {
                        // Check if workflow name is unique.
                        if (!string.IsNullOrEmpty(currentEnteredName) && this.CheckIfWfNameIsUnique(this.categoryPicker.SelectedModel, currentEnteredName))
                        {
                            validUpdate = true;
                            this.UpdateWfNameOnValidEntry();
                        }
                        else
                        {
                            validUpdate = false;
                        }
                    }

                    if (validUpdate)
                    {
                        this.isWorkflowCategoryValid = true;
                    }
                    else
                    {
                        this.isWorkflowCategoryValid = false;
                    }

                    this.SetCategory();
                    this.CategoryNameHolder = this.categoryPicker.SelectedModel.Label;
                    this.isWorkflowCategoryValid = validUpdate;
                    this.ChangeWfCategoryErrorMarkerVisibility(!validUpdate, TridentResourceManager.GetString("PropertyPaneCategoryContainsName"));
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.HandleKnownExceptionsInUI(ex);
                }
            }

            if (this.categoryPickerWindow != null)
            {
                this.categoryPickerWindow.Close();
            }
        }

        /// <summary>
        /// Closes the category picker.
        /// </summary>
        /// <param name="sender">
        /// Category picker.
        /// </param>
        /// <param name="e">
        /// EventArgs.
        /// </param>
        private void OnCategoryPickerCancel(object sender, EventArgs e)
        {
            if (this.categoryPickerWindow != null)
            {
                this.categoryPickerWindow.Close();
            }
        }

        /// <summary>
        /// On valid entry of the workflow name, the binding gets updated and the error marker is removed.
        /// </summary>
        private void UpdateWfNameOnValidEntry()
        {
            if (!string.IsNullOrEmpty(this.txtBxWfName.Text))
            {
                BindingExpression bindingExp = this.txtBxWfName.GetBindingExpression(TextBox.TextProperty);
                if (bindingExp != null)
                {
                    this.txtBxWfName.ToolTip = this.txtBxWfName.Text;
                    bindingExp.UpdateSource();
                    this.isWorkflowNameValid = true;
                    DockPanel errorWfName = (this.txtBxWfName.Parent as Grid).FindName("errorWfName") as DockPanel;
                    if (errorWfName != null)
                    {
                        errorWfName.Visibility = Visibility.Collapsed;
                    }
                }
            }
        }

        /// <summary>
        /// Check if the workflow of the particular name exists in the category selected.
        /// </summary>
        /// <param name="categoryModelToCheckIn">
        /// The category in which to check.
        /// </param>
        /// <param name="wfName">
        /// The name to check against.
        /// </param>
        /// <returns>
        /// True indicating the name is unique, false indicating that a workflow of the same name already exists.
        /// </returns>
        private bool CheckIfWfNameIsUnique(WorkflowCategoryModel categoryModelToCheckIn, string wfName)
        {
            if (this.wfModel.Id.Equals(Guid.Empty) && this.wfModel.WorkflowToUpdate.Equals(Guid.Empty))
            {
                return CategoriesComposer.ValidateWorkflowName(categoryModelToCheckIn.Id, wfName.Trim(), this.registryConnection);
            }
            else
            {
                // Check if the workflow has been marked to update a existing. If so we can allow the same name.
                Guid idToCheckAgainst = this.wfModel.Id.Equals(Guid.Empty) ? this.wfModel.WorkflowToUpdate : this.wfModel.Id;
                return CategoriesComposer.ValidateWorkflowName(categoryModelToCheckIn.Id, idToCheckAgainst, wfName.Trim(), this.registryConnection);
            }
        }

        /// <summary>
        /// Change the visibility of the workflow category error marker.
        /// </summary>
        /// <param name="makeVisible">
        /// If true, make it visible, else collapse it.
        /// </param>
        /// <param name="errorPrompt">
        /// The error prompt to be displayed to the user.
        /// </param>
        private void ChangeWfCategoryErrorMarkerVisibility(bool makeVisible, string errorPrompt)
        {
            DockPanel errorWfCategory = (this.txtBxWfCategory.Parent as Grid).FindName("errorWfCategory") as DockPanel;
            if (errorWfCategory != null)
            {
                if (makeVisible)
                {
                    errorWfCategory.Visibility = Visibility.Visible;
                    errorWfCategory.ToolTip = errorPrompt;
                    this.txtBxWfCategory.ToolTip = errorPrompt;
                }
                else
                {
                    errorWfCategory.Visibility = Visibility.Collapsed;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnPropertiesPaneLoaded(object sender, RoutedEventArgs e)
        {
            this.GetComposerControl();
            this.txtBxWfName.SelectAll();
            this.txtBxWfName.Focus();
        }

        /// <summary>
        /// Get the composer control instance.
        /// </summary>
        private void GetComposerControl()
        {
            string composerCtrlName = (string)this.GetValue(ComposerControl.ComposerControlNameProperty);
            this.composerCtrl = Application.Current.MainWindow.FindName(composerCtrlName) as ComposerControl;

            if (this.listVw != null)
            {
                this.listVw.ComposerControl = this.composerCtrl;
            }
        }

        /// <summary>
        /// Fired on load of the error marker.
        /// </summary>
        /// <param name="sender">
        /// Error marker.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnErrorMarkerLoaded(object sender, RoutedEventArgs e)
        {
            DockPanel senderDock = sender as DockPanel;
            if (senderDock != null)
            {
                ParameterDescriptionModel paramModel = senderDock.DataContext as ParameterDescriptionModel;
                if (paramModel != null && !this.paramsToValidate.Contains(paramModel))
                {
                    this.paramsToValidate.Add(paramModel);
                }
            }
        }

        /// <summary>
        /// Fired on text changed of the value textbox.
        /// </summary>
        /// <param name="sender">
        /// Textbox.
        /// </param>
        /// <param name="e">
        /// TextChangedEventArgs.
        /// </param>
        private void OnValueTextChanged(object sender, TextChangedEventArgs e)
        {
            this.OnWfNameTextBoxLostFocus(sender, new RoutedEventArgs());
        }

        /// <summary>
        /// Iterates through the parameters and checks if all values are valid.
        /// </summary>
        /// <returns>True if all values are valid. False otherwise.</returns>
        private bool CheckIfAllValuesValid()
        {
            ParameterDescriptionModel model = this.paramsToValidate.FirstOrDefault(p => !p.IsDatabound && p.IsValueInvalid);
            return model == null ? true : false;
        }

        /// <summary>
        /// Fired on cancel click of the pop-up.
        /// </summary>
        /// <param name="sender">
        /// Cancel button.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnCancelClick(object sender, RoutedEventArgs e)
        {
            if (this.wfModel != null && this.backUpWfModel != null)
            {
                if (this.wfModel.Id == Guid.Empty)
                {
                    this.wfModel.Id = this.backUpWfModel.Id;
                }

                if (string.IsNullOrEmpty(this.backUpWfModel.Name))
                {
                    this.wfModel.Name = string.Empty;
                }
                else if (!this.wfModel.Name.Equals(this.backUpWfModel.Name, StringComparison.CurrentCulture))
                {
                    this.wfModel.Name = this.backUpWfModel.Name;
                }

                if (string.IsNullOrEmpty(this.backUpWfModel.Description))
                {
                    this.wfModel.Description = string.Empty;
                }
                else if (!this.wfModel.Description.Equals(this.backUpWfModel.Description, StringComparison.CurrentCulture))
                {
                    this.wfModel.Description = this.backUpWfModel.Description;
                }

                if (null == this.backUpWfModel.Category)
                {
                    this.wfModel.Category = null;
                }
                else if (!this.wfModel.Category.Equals(this.backUpWfModel.Category))
                {
                    this.wfModel.Category = this.backUpWfModel.Category;
                }

                foreach (BaseModel model in this.wfModel.ModelsHashtable.Values)
                {
                    if (model.IsSimpleActivityModel)
                    {
                        PropertiesPane.RevertActivityParametersOnCancel(this.backUpWfModel.ModelsHashtable[model.UniqueId] as SimpleActivityModel, model as SimpleActivityModel);
                    }
                    else if (model.IsCompositeActivityModel)
                    {
                        PropertiesPane.RevertActivityParametersOnCancel(this.backUpWfModel.ModelsHashtable[model.UniqueId] as CompositeActivityModel, model as CompositeActivityModel);
                    }
                }
            }

            if (this.ClosePropPane != null)
            {
                this.ClosePropPane.Invoke(this, e);
            }
        }

        /// <summary>
        /// Revert the parameter input values changes.
        /// </summary>
        /// <param name="backUpModel">
        /// The old model (simple).
        /// </param>
        /// <param name="currentModel">
        /// The current model (simple).
        /// </param>
        private static void RevertActivityParametersOnCancel(SimpleActivityModel backUpModel, SimpleActivityModel currentModel)
        {
            if (backUpModel != null && currentModel != null)
            {
                PropertiesPane.RevertParams(backUpModel.InputParameters, currentModel.InputParameters);
            }
        }

        /// <summary>
        /// Revert the parameter input values changes.
        /// </summary>
        /// <param name="backUpModel">
        /// The old model (composite).
        /// </param>
        /// <param name="currentModel">
        /// The current model (composite).
        /// </param>
        private static void RevertActivityParametersOnCancel(CompositeActivityModel backUpModel, CompositeActivityModel currentModel)
        {
            if (backUpModel != null && currentModel != null)
            {
                PropertiesPane.RevertParams(backUpModel.InputParameters, currentModel.InputParameters);
            }
        }

        /// <summary>
        /// Copy the old params into the current params list.
        /// </summary>
        /// <param name="oldParams">
        /// Old parameters.
        /// </param>
        /// <param name="newParams">
        /// Current or New parameters.
        /// </param>
        private static void RevertParams(Collection<ParameterDescriptionModel> oldParams, Collection<ParameterDescriptionModel> newParams)
        {
            for (int iterator = 0; iterator < oldParams.Count; iterator++)
            {
                if (null == oldParams[iterator].Value)
                {
                    newParams[iterator].Value = null;
                    continue;
                }

                if (!oldParams[iterator].Value.Equals(newParams[iterator].Value))
                {
                    if (oldParams[iterator].IsDatabound)
                    {
                        DatabindModel currentDataBindModel = newParams[iterator].Value as DatabindModel;
                        if (currentDataBindModel != null)
                        {
                            DatabindModel backUpDatabindModel = oldParams[iterator].Value as DatabindModel;
                            if (backUpDatabindModel != null)
                            {
                                currentDataBindModel.SourceActivityName = backUpDatabindModel.SourceActivityName;
                                currentDataBindModel.SourcePropertyName = backUpDatabindModel.SourcePropertyName;
                            }
                        }
                    }
                    else
                    {
                        newParams[iterator].Value = oldParams[iterator].Value;
                    }
                }
            }
        }

        /// <summary>
        /// Create the cloned back up of the workflowModel passed.
        /// </summary>
        private void CreateWfModelBackUp()
        {
            if (null == this.wfModel)
            {
                this.backUpWfModel = null;
            }
            else if (null == this.backUpWfModel || !(this.backUpWfModel.Root.UniqueId.Equals(this.wfModel.Root.UniqueId, StringComparison.OrdinalIgnoreCase)))
            {
                this.backUpWfModel = TridentWorkflowModel.CreateClone(this.wfModel);
            }
        }

        /// <summary>
        /// Fired on click of the custom type initializer button.
        /// </summary>
        /// <param name="sender">
        /// The custom type initializer button.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnCustomTypeInitClick(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            DockPanel panel = btn.Parent as DockPanel;
            if (panel != null)
            {
                TextBox box = panel.FindName("txtBxParamValue") as TextBox;
                if (box != null)
                {
                    MultiBindingExpression multiBindingExp = BindingOperations.GetMultiBindingExpression(box, TextBox.TextProperty);
                    if (multiBindingExp != null)
                    {
                        BindingExpression bindingExp = multiBindingExp.BindingExpressions[0] as BindingExpression;
                        if (bindingExp != null)
                        {
                            ParameterDescriptionModel paramDesc = (multiBindingExp.BindingExpressions[0] as BindingExpression).DataItem as ParameterDescriptionModel;
                            if (paramDesc != null)
                            {
                                try
                                {
                                    TypeInitializer typeInit = TypeProviderHelper.FetchTypeInitializer(paramDesc.DataType, Runtime.WPF);
                                    if (typeInit != null)
                                    {
                                        string deserializedVal = (paramDesc.Value != null) ? paramDesc.Value.ToString() : string.Empty;
                                        TypeInitializerContainer typeInitContainer = new TypeInitializerContainer();
                                        BaseTypeInitializer baseTypeinit = typeInitContainer.DoModal(typeInit, deserializedVal);
                                        if (baseTypeinit != null)
                                        {
                                            paramDesc.Value = baseTypeinit.GetSerializedVersion(baseTypeinit.GetValue());
                                            bindingExp.UpdateTarget();
                                            MultiBindingExpression multiBindingExpTooltip = BindingOperations.GetMultiBindingExpression(box, ToolTipProperty);
                                            if (multiBindingExpTooltip != null)
                                            {
                                                BindingExpression bindingExpTooltip = multiBindingExpTooltip.BindingExpressions[0] as BindingExpression;
                                                if (bindingExpTooltip != null)
                                                {
                                                    bindingExpTooltip.UpdateTarget();
                                                }
                                            }

                                            if (this.composerCtrl != null)
                                            {
                                                this.composerCtrl.IsWFCommitted = false;
                                            }
                                        }
                                    }
                                }
                                catch (TridentCustomException ex)
                                {
                                    TridentMessageBox.ShowTridentErrorMessageBox(ex.Message);
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Called when mouse down occurs on the header.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void OnHeaderMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (this.OnPropPaneDrag != null)
            {
                this.OnPropPaneDrag.Invoke(sender, e);
            }
        }

        #endregion Private Methods

        #region INotifyPropertyChanged Members

        /// <summary>
        /// The property changed event. Fired when a proprty value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Fires the property changed event.
        /// </summary>
        /// <param name="propertyName">Name of the property which has been modified</param>
        private void OnNotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        private void TextBox_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
        {
            e.Handled = true;
        }
    }

    public enum PropertyPaneMode
    {
        Popup,
        Dockable,
        Fixed
    }
}